Day 14 第一次認真看 Figma。
昨天在 CRM UI Kit 的登入畫面裡,我點到包住兩顆按鈕的 Frame,右邊看到:
Auto layout
Flow: Horizontal
Width: Fill
Height: Hug
Gap: 9
Padding: 0
昨天先停在「看懂」。
今天不想再只用文字解釋,所以我把昨天的 Figma 節點重新打開,然後真的開 React 專案動手做。
核心問題很簡單:
Figma 裡看到的 Horizontal、Fill、Hug、Gap 9,到了 React 到底要怎麼寫?
我以前看到這種東西:
<div className="flex w-full gap-[9px]">
第一個反應其實是:這又是哪一套語法?
這裡其實混合了兩件事情:
className
→ React / JSX 用來指定 CSS class 的寫法
→ 一般 HTML 裡會寫成 class
而 className 裡面的:
flex
→ display: flex
w-full
→ width: 100%
gap-[9px]
→ gap: 9px
所以這整句:
<div className="flex w-full gap-[9px]">
大概可以先把它想成:
<div
style={{
display: "flex",
width: "100%",
gap: "9px",
}}
>
Tailwind CSS 是 CSS framework,但它不是另一套瀏覽器排版引擎。
瀏覽器最後跑的還是 CSS。
Tailwind 比較像是把常用 CSS 規則整理成很多小工具,讓我直接在 JSX 的 className 裡組起來。
這裡的 [9px] 可以先記成:Tailwind 允許直接指定任意值。後面實際做到 Gap 9 時,再仔細看它代表什麼。
Tailwind 並沒有讓瀏覽器突然多出新的排版能力。
它主要改變的是工程師組 UI 的方式。
一般 CSS 常常會是:
看到 Figma
↓
想成 CSS
↓
幫這塊 UI 取一個 class 名稱
↓
切到 CSS 檔案寫規則
↓
回 JSX 掛上 class
如果專案使用 Tailwind,就可以比較直接:
看到 Figma
↓
想成 CSS
↓
在 JSX 裡用 utility class 組出來
例如:
<div className="flex w-full gap-[9px]">
對 React 這種元件化開發來說,樣式和元件會放得比較近。我們在調畫面時,也比較不用一直在 JSX 和 CSS 檔案之間來回找。
另外,正式專案通常還會把 spacing、顏色、字體、圓角等規則整理成 design system。
這時 Tailwind 的 gap-2、px-4、rounded-xl 這類 utility class,也能幫大家比較容易沿用同一套尺度。
但 Tailwind 不是「一定比較好」。
當 class 很多時:
<button className="flex items-center justify-center rounded-xl border px-4 py-3 font-semibold ...">
也可能變得很長。
所以我現在先把它理解成:
Tailwind 不是取代 CSS,而是一種讓我們更快組合 CSS 規則的工作方式。
這次直接用這個系列的 vite-why-lab 做實驗。
安裝:
npm install -D tailwindcss @tailwindcss/vite
接著在 vite.config.js 加上 Tailwind 的 Vite plugin:
import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
})
src/index.css 則先縮到最小:
@import "tailwindcss";
這次不是「文章裡假設有 Tailwind」。
我真的跑了:
npm run build
Vite build 有成功,才繼續下面的實驗。
我先故意不寫 Tailwind:
function App() {
return (
<main>
<h1>Day 15 Tailwind Lab</h1>
<div>
<button>Sign In</button>
<button>Sign Up</button>
</div>
</main>
)
}
畫面真的很樸素。
但這反而很重要。
因為接下來每加一個 class,我都可以直接看它到底改了什麼。
flex昨天 Figma 顯示:
Flow: Horizontal
如果翻成 CSS 心智模型,大概就是:
display: flex;
Tailwind 寫法:
<div className="flex">
<button>Sign In</button>
<button>Sign Up</button>
</div>
所以這一次我不是背:
flex = 橫排
而是知道:
Figma Horizontal Auto Layout
↓
CSS Flexbox
↓
Tailwind flex
gap-[9px]接著是昨天真的看到的:
Gap: 9
先直接做最忠實的版本:
<div className="flex gap-[9px]">
這裡的方括號代表我直接指定任意值。
但這不代表以後 Figma 看到 9px,就永遠都要寫 gap-[9px]。
正式專案通常會有 spacing scale,例如 8px、12px、16px。
設計系統如果已經有接近的規則,可能會選既有 spacing,而不是讓每個地方都長出一個神奇數字。
今天先忠實重現,之後再談 design system。
w-full這是昨天最容易誤會的地方。
Figma 的 Fill 比較像「尺寸策略」:
父層能分給我多少空間,我就去使用那些空間。
例如外層容器要吃滿可用寬度,可以是:
<div className="w-full">
但是兩顆按鈕要一起平分空間時,我反而用了:
<button className="flex-1">Sign In</button>
<button className="flex-1">Sign Up</button>
所以不能死背:
Figma Fill = Tailwind w-full
要先看父層怎麼排。
Figma 還寫了:
Height: Hug
如果我只看到畫面最後高度大概 46px,就直接:
className="h-[46px]"
反而可能把 Hug 的意思弄丟。
這次按鈕是靠:
className="px-4 py-3"
讓「文字高度 + 上下 padding」自然把按鈕撐開。
內容改變時,元件還能跟著長。
這比把每顆按鈕高度硬鎖死,更接近 Hug contents 的思維。
<div className="flex w-full gap-[9px]">
<button className="flex-1 rounded-xl bg-violet-600 px-4 py-3 font-semibold text-white">
Sign In
</button>
<button className="flex-1 rounded-xl border border-slate-300 bg-white px-4 py-3 font-semibold">
Sign Up
</button>
</div>
這次程式碼也不是只存在文章裡。
我是真的在 App.jsx 裡把這些 Tailwind class 寫進去。
flex
→ 子元素用 Flexbox 排列
w-full
→ 使用可用寬度
gap-[9px]
→ 子元素之間 9px
flex-1
→ 一起分配剩餘空間
rounded-xl
→ 圓角
px-4 / py-3
→ 左右 / 上下 padding
font-semibold
→ 字體稍粗
最大的差別不是今天多背了幾個 class。
而是開始能走:
Figma
↓
Layout 規則
↓
CSS 心智模型
↓
Tailwind
↓
React JSX
而不是:
Figma 看到 9px
↓
找一個 Tailwind 9px
↓
貼上
現在兩顆按鈕已經有樣子了。
但是按下 Sign In 之後,目前什麼事情都不會發生。
假設登入前:
const user = null
登入後:
const user = {
name: 'Anthony'
}
React 要怎麼知道資料變了,而且畫面也應該跟著更新?
這就會碰到下一個問題:
登入狀態為什麼不能只寫成普通的
const?React 的 state 到底在解決什麼?
這就是 Day 16 要接的地方。